class auth {

	async checkSign(uri, ...datas) {
		try {
			let data = {}
			let sessionData = {}
			for(let _data of datas)
				Object.assign(data, _data)
			console.log(data)
			if(!data || !data.grantType || ['token', 'key'].indexOf(data.grantType) == -1 || !data.sign || data.sign.length != 32)
				return this.reject('-1025', 'sign error')
			//API失效时间，如果没定义将为5分钟
			let apiExpires = this.config.frame.apiExpires[uri] || this.config.frame.apiExpires.all || 300
			if(!data.timestamp || !data.nonce || isNaN(data.timestamp) || data.nonce.length != 10 || (this.common.timestamp() - Math.abs(parseInt(data.timestamp))) > apiExpires)
				return this.reject('-1030', 'sign timeout')
			let sign = ''
			let signStr = ''
			let keys = Object.keys(data)
			if(keys.length == 1) {
				return this.reject('-1026', 'sign error')
			}
			keys = keys.sort()
			console.log(keys)
			for(let key of keys) {
				if(key == 'sign') {
					sign = data[key]
				}
				else if(!isNaN(key)) {
					continue
				}
				else if(Object.prototype.toString.call(data[key]) == '[object Object]' || Object.prototype.toString.call(data[key]) == '[object Array]') {
					signStr += `&${key}=${JSON.stringify(data[key])}`
				}
				else {
					signStr += `&${key}=${encodeURI(data[key])}`
				}
			}
			switch(data.grantType) {
				case 'token':
					if(!data.session || !/([a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}?)/i.test(data.session))
						return this.reject('-1004', `request interface permission denied`)
					let user = await this.redis.session.get(data.session, true)
					console.log('user info:', user)
					if(!user || !user.type || !user.token || user.token.length != 10 || !user.data) {
						return this.reject('-1004', `request interface permission denied`)
					}
					signStr += `&token=${user.token}`
					user.session = data.session
					sessionData = user
				break
				case 'key':
					if(data.appId) {
						return this.reject('-1035', 'sign appid invalid')
					}
					signStr += `&key=${this.config.frame.apiKeys[data.appId]}`
				break
			}
			signStr = this.common.ltrim(signStr, '&')
			console.log('no sign string:', signStr)
			signStr = this.crypto.md5(signStr)
			console.log('signed string:', signStr)
			if(sign == signStr) {
				if(this.config.frame.apiStrict) {
					let nonce = await this.redis.system.get(`nonce@${data.nonce}`)
					if(nonce)
						return this.reject('-1043', 'sign error')
					else
						await this.redis.system.set(`nonce@${data.nonce}`, {session: data.session}, apiExpires)
				}
				console.log(`${data.grantType} sign success`)
				return this.resolve(sessionData)
			}
			else {
				console.error('sign error')
				return this.reject('-1028', 'sign error')
			}
		}
		catch(err) {
			console.error(err)
			return this.reject('-1027', 'sign error')
		}
	}

	async allow(...userTypes) {
		let user, nosign = userTypes.indexOf('nosign') != -1
		if(!nosign)
			user = await this.checkSign(this.uri, this.bodyData, this.queryData)

		//解密query数据
		if(this.queryData.encryptData && this.queryData.iv && this.queryData.encryptKey) {
			console.log('decrypt key:', this.queryData.encryptKey)
			const key = this.crypto.decryptRSA(this.queryData.encryptKey)
			const iv = Buffer.from(this.queryData.iv, 'base64').toString()
			const result = this.crypto.decryptAES(this.queryData.encryptData, key, iv)
			const temp = this.common.isJson(result)
			this.ctx.queryData = temp ? temp : result
			this.ctx.resEncryptData = { key, iv }
		}

		//解密body数据
		if(this.bodyData.encryptData && this.bodyData.iv && this.bodyData.encryptKey) {
			console.log('decrypt key:', this.bodyData.encryptKey)
			const key = this.crypto.decryptRSA(this.bodyData.encryptKey)
			const iv = Buffer.from(this.bodyData.iv, 'base64').toString()
			const result = this.crypto.decryptAES(this.bodyData.encryptData, key, iv)
			console.log(result)
			const temp = this.common.isJson(result)
			this.ctx.bodyData = temp ? temp : result
			this.ctx.resEncryptData = { key, iv }
		}

		if(nosign)
			return {}

		if(!user || !user.type || (userTypes[0] != 'all' && userTypes.indexOf(user.type) == -1)) {
			this.status = 403
			console.error(`user ${user.type}:${user.userId || 'unknown'} request interface permission denied`)
			return this.reject('-1038', 'user cannot request this interface')
		}

		this.ctx.user = user

		return this.resolve(user)
	}

}

module.exports = auth